package queue

import (
	"APT/internal/consts"
	"APT/internal/dao"
	_ "APT/internal/logic"
	"APT/internal/model"
	"APT/internal/model/entity"
	"APT/internal/model/input/input_app_member"
	"APT/internal/service"
	"APT/utility/rabbitmq"
	"context"
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
	_ "github.com/gogf/gf/contrib/nosql/redis/v2"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/guid"
	amqp "github.com/rabbitmq/amqp091-go"
	"github.com/shopspring/decimal"
)

var (
	RebateLogger = g.Log().Path("logs/MQ/" + consts.RabbitMQQueueNameRebate)
)

func Rebate() {
	var (
		ctx          = gctx.New()
		MQMsg        <-chan amqp.Delivery
		exchangeName = consts.RabbitMQExchangeName
		QueueName    = consts.RabbitMQQueueNameRebate
		MQConnStruct *rabbitmq.MQConnection
		err          error
	)
	g.DB().SetLogger(RebateLogger)
	MQConnStruct = &rabbitmq.MQConnection{
		Conn:         rabbitmq.Conn,
		Chan:         nil,
		ExchangeName: exchangeName,
		QueueName:    QueueName,
		RouteKey:     fmt.Sprintf("%s.%s.%s", exchangeName, consts.RabbitMQGB, QueueName),
	}
	if err = MQConnStruct.Channel(); err != nil {
		err = gerror.New("创建队列失败")
		goto ERR
	}
	if err = MQConnStruct.Exchange("topic", true, false); err != nil {
		err = gerror.New("创建交换机失败")
		goto ERR
	}
	if err = MQConnStruct.Queue(true, false, nil); err != nil {
		err = gerror.New("创建通道失败")
		goto ERR
	}
	if err = MQConnStruct.Bind(); err != nil {
		err = gerror.New("交换机绑定队列失败")
		goto ERR
	}
	RebateLogger.Info(ctx, "Rebate Queue START SUCCESSFUL")
	if MQMsg, err = MQConnStruct.Consume(guid.S(), false); err != nil {
		RebateLogger.Error(ctx, err.Error())
		return
	}
	for msg := range MQMsg {
		ctx = gctx.New()
		RebateLogger.Info(ctx, "--[start]----------------------------------------------")
		RebateLogger.Info(ctx, msg.Body)
		if string(msg.Body)[:1] == "H" {
			if err = HandleReturnBrokerageMQ(ctx, msg); err != nil {
				RebateLogger.Error(ctx, err.Error())
			}
			if err = HandleHotelReturnScore(ctx, msg); err != nil {
				RebateLogger.Error(ctx, err.Error())
			}
			if err = HandleInviteAward(ctx, msg); err != nil {
				RebateLogger.Error(ctx, err.Error())
			}
		}
		if string(msg.Body)[:1] == "F" {
			if err = HandleFoodReturnScore(ctx, msg); err != nil {
				RebateLogger.Error(ctx, err.Error())
			}
		}
		if string(msg.Body)[:1] == "C" {
			if err = HandleCarReturnScore(ctx, msg); err != nil {
				RebateLogger.Error(ctx, err.Error())
			}
		}
		if string(msg.Body)[:1] == "S" {
			if err = HandleSpaReturnScore(ctx, msg); err != nil {
				RebateLogger.Error(ctx, err.Error())
			}
		}

		_ = msg.Ack(false)
	}
ERR:
	RebateLogger.Error(ctx, err)
	panic(err)
}

// HandleReturnBrokerageMQ 用户下单推荐人返佣金
func HandleReturnBrokerageMQ(ctx context.Context, msg amqp.Delivery) (err error) {
	var (
		body             = msg.Body
		OrderSn          string
		StayInfo         *entity.PmsAppStay
		CheckStayInfo    *entity.PmsAppStay
		checkinStatusVar *gvar.Var
		ReferrerInfo     *entity.PmsMember
		MemberInfo       *entity.PmsMember
		ChannelInfo      *entity.PmsChannel
		StaffInfo        *entity.PmsStaff
		YYConfig         *model.YYConfig
		PayAmount        float64
		RefundAmount     float64
	)
	OrderSn = gvar.New(body).String()
	if g.IsEmpty(OrderSn) {
		err = gerror.New("订单号为空")
		return
	}

	if err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		RebateLogger.Info(ctx, "检测订单信息")
		// 查询 app 订单信息
		if err = dao.PmsAppStay.Ctx(ctx).TX(tx).
			Where(dao.PmsAppStay.Columns().OrderSn, OrderSn).
			Scan(&StayInfo); err != nil {
			return
		}
		if g.IsEmpty(StayInfo) {
			err = gerror.New("住宿订单数据为空")
			return
		}
		if StayInfo.RebateStatus != "WAIT" {
			err = gerror.New("订单状态不为佣金处理中")
			return
		}
		if g.IsEmpty(StayInfo.Referrer) {
			err = gerror.New("没有推荐人无需处理佣金")
			return
		}
		// 查询下单人信息
		if err = dao.PmsMember.Ctx(ctx).TX(tx).Where(dao.PmsMember.Columns().Id, StayInfo.MemberId).Scan(&MemberInfo); err != nil && !errors.Is(err, sql.ErrNoRows) {
			return
		}
		// 判断是否用户首单
		if err = dao.PmsAppStay.Ctx(ctx).
			Where(dao.PmsAppStay.Columns().MemberId, StayInfo.MemberId).
			Where(dao.PmsAppStay.Columns().OrderStatus, "HAVE_PAID").
			OrderAsc(dao.PmsAppStay.Columns().Id).
			Scan(&CheckStayInfo); err != nil {
			return
		}
		if g.IsEmpty(CheckStayInfo) {
			RebateLogger.Info(ctx, "无订单不需要处理")
		}

		if CheckStayInfo.OrderSn == OrderSn && MemberInfo.Referrer != StayInfo.Referrer {
			// 首单第一次推荐人是否存在
			if err = dao.PmsMember.Ctx(ctx).TX(tx).Where(dao.PmsMember.Columns().Id, StayInfo.Referrer).Scan(&ReferrerInfo); err != nil && !errors.Is(err, sql.ErrNoRows) {
				return
			}
			if g.IsEmpty(ReferrerInfo) {
				err = gerror.New("推荐人不存在")
				return
			}
			// 是首单的情况下  结算给初次推荐人 并更新
			if YYConfig, err = service.BasicsConfig().GetYYConfig(ctx); err != nil {
				return err
			}
			// 计算新推荐人的佣金比例
			if !g.IsEmpty(ReferrerInfo) {
				PmsAppStayData := &entity.PmsAppStay{
					RebateStatus: "WAIT",
					RebateRate:   0,
				}
				PmsAppStayData.RebateStatus = "WAIT"
				if ReferrerInfo.RebateMode == "CHANNEL" {
					if err = dao.PmsChannel.Ctx(ctx).WherePri(ReferrerInfo.ChannelId).Scan(&ChannelInfo); err != nil {
						return err
					}
					if !g.IsEmpty(ChannelInfo) {
						PmsAppStayData.RebateRate = ChannelInfo.Rate
					}
				} else if ReferrerInfo.RebateMode == "STAFF" {
					if err = dao.PmsStaff.Ctx(ctx).WherePri(ReferrerInfo.StaffId).Scan(&StaffInfo); err != nil {
						return err
					}
					if !g.IsEmpty(StaffInfo) {
						PmsAppStayData.RebateRate = StaffInfo.Rate
					}
				} else if ReferrerInfo.RebateMode == "MEMBER" {
					PmsAppStayData.RebateRate = YYConfig.MemberBrokerageRate
				} else {
					return gerror.New("不存在该返佣模式")
				}

				// 更新订单返佣信息
				_, err = dao.PmsAppStay.Ctx(ctx).TX(tx).Where(dao.PmsAppStay.Columns().OrderSn, OrderSn).Data(PmsAppStayData).Update()
			}
			// 重新查询订单信息
			// 查询 app 订单信息
			if err = dao.PmsAppStay.Ctx(ctx).TX(tx).
				Where(dao.PmsAppStay.Columns().OrderSn, OrderSn).
				Scan(&StayInfo); err != nil {
				return
			}
			if g.IsEmpty(StayInfo) {
				err = gerror.New("住宿订单数据为空")
				return
			}
		}
		if checkinStatusVar, err = dao.PmsAppReservation.Ctx(ctx).TX(tx).
			Where(dao.PmsAppReservation.Columns().OrderSn, OrderSn).
			Group(dao.PmsAppReservation.Columns().CheckinStatus).
			Fields("GROUP_CONCAT(checkin_status) as checkin_status").
			Value(); err != nil {
			return
		}
		if checkinStatusVar.String() != "checked_out" {
			err = gerror.New("订单未完结无法计算佣金")
			return
		}
		RebateLogger.Info(ctx, "结算佣金")
		// 查询订单外部支付退款和外部支付信息
		if PayAmount, err = dao.PmsTransaction.Ctx(ctx).TX(tx).
			Where(dao.PmsTransaction.Columns().OrderSn, OrderSn).
			WhereNot(dao.PmsTransaction.Columns().PayType, "BAL").
			Where(dao.PmsTransaction.Columns().PayStatus, "DONE").
			Group(dao.PmsTransaction.Columns().OrderSn).
			Sum(dao.PmsTransaction.Columns().PayAmount); err != nil {
			return
		}
		if PayAmount <= 0 {
			err = gerror.New("未产生除积分外的支付信息无法进行结算佣金")
			return
		}
		if RefundAmount, err = dao.PmsTransactionRefund.Ctx(ctx).TX(tx).
			Where(dao.PmsTransactionRefund.Columns().OrderSn, OrderSn).
			WhereNot(dao.PmsTransactionRefund.Columns().RefundType, "BAL").
			Where(dao.PmsTransactionRefund.Columns().RefundStatus, "DONE").
			Group(dao.PmsTransactionRefund.Columns().OrderSn).
			Sum(dao.PmsTransactionRefund.Columns().RefundAmount); err != nil {
			return
		}
		RebatePrice := decimal.NewFromFloat(PayAmount).Sub(decimal.NewFromFloat(RefundAmount)).Round(0).InexactFloat64()
		RebatePrice = decimal.NewFromFloat(RebatePrice).Mul(decimal.NewFromFloat(StayInfo.RebateRate)).Div(decimal.NewFromFloat(100)).Round(0).InexactFloat64()
		if RebatePrice == 0 {
			err = gerror.New("订单金额不足无法进行结算佣金")
			return
		}
		if _, err = dao.PmsAppStay.Ctx(ctx).TX(tx).Data(g.Map{
			dao.PmsAppStay.Columns().RebateStatus: "SUCCESS",
			dao.PmsAppStay.Columns().RebateAmount: RebatePrice,
			dao.PmsAppStay.Columns().RebateTime:   gtime.Now(),
		}).Where(dao.PmsAppStay.Columns().Id, StayInfo.Id).Update(); err != nil {
			return
		}
		// 查看推荐人信息
		if err = dao.PmsMember.Ctx(ctx).TX(tx).Where(dao.PmsMember.Columns().Id, StayInfo.Referrer).Scan(&ReferrerInfo); err != nil && !errors.Is(err, sql.ErrNoRows) {
			return
		}
		if g.IsEmpty(ReferrerInfo) {
			err = gerror.New("推荐人不存在无法结算佣金")
			return
		}
		if ReferrerInfo.RebateMode == "STAFF" {
			// 增加结算账户佣金
			if _, err = dao.PmsStaff.Ctx(ctx).TX(tx).
				Where(dao.PmsStaff.Columns().Id, ReferrerInfo.StaffId).
				Increment(dao.PmsStaff.Columns().Balance, RebatePrice); err != nil {
				return
			}
			// 增加历史账户佣金
			if _, err = dao.PmsStaff.Ctx(ctx).TX(tx).
				Where(dao.PmsStaff.Columns().Id, ReferrerInfo.StaffId).
				Increment(dao.PmsStaff.Columns().AllBalance, RebatePrice); err != nil {
				return
			}
			// 增加结算账户佣金变动记录
			if _, err = dao.PmsBrokerage.Ctx(ctx).Data(&entity.PmsBrokerage{
				Identity:  "STAFF",
				Type:      "REBATE",
				Balance:   RebatePrice,
				StaffId:   ReferrerInfo.StaffId,
				ChannelId: 0,
				MemberId:  ReferrerInfo.Id,
			}).OmitEmptyData().InsertAndGetId(); err != nil {
				return
			}
		}
		if ReferrerInfo.RebateMode == "CHANNEL" {
			// 增加结算账户佣金
			if _, err = dao.PmsChannel.Ctx(ctx).TX(tx).Where(dao.PmsChannel.Columns().Id, ReferrerInfo.ChannelId).Increment(dao.PmsChannel.Columns().Balance, RebatePrice); err != nil {
				return
			}
			// 增加结算账户佣金
			if _, err = dao.PmsChannel.Ctx(ctx).TX(tx).Where(dao.PmsChannel.Columns().Id, ReferrerInfo.ChannelId).Increment(dao.PmsChannel.Columns().AllBalance, RebatePrice); err != nil {
				return
			}
			// 增加结算账户佣金变动记录
			if _, err = dao.PmsBrokerage.Ctx(ctx).Data(&entity.PmsBrokerage{
				Identity:  "CHANNEL",
				Type:      "REBATE",
				Balance:   RebatePrice,
				StaffId:   0,
				ChannelId: ReferrerInfo.ChannelId,
				MemberId:  ReferrerInfo.Id,
			}).OmitEmptyData().InsertAndGetId(); err != nil {
				return
			}
		}
		if ReferrerInfo.RebateMode == "MEMBER" {
			if err = service.AppMember().MemberBalanceChange(ctx, &input_app_member.MemberBalanceInp{
				MemberId:      ReferrerInfo.Id,
				Scene:         "HOTEL",
				Type:          "AWARD",
				ChangeBalance: RebatePrice,
				OrderSn:       StayInfo.OrderSn,
				Des:           "推荐人下单返现",
			}, tx); err != nil {
				return err
			}
		}
		RebateLogger.Info(ctx, "RUN_SUCCESS_ReturnBrokerage")
		return err
	}); err != nil {
		RebateLogger.Info(ctx, "RUN_FAIL_ReturnBrokerage")
		return err
	}
	return
}

// HandleHotelReturnScore 用户下单返积分
func HandleHotelReturnScore(ctx context.Context, msg amqp.Delivery) (err error) {
	var (
		body         = msg.Body
		OrderSn      string
		StayInfo     *entity.PmsAppStay
		YYConfig     *model.YYConfig
		PayAmount    float64
		RefundAmount float64
	)
	OrderSn = gvar.New(body).String()
	if g.IsEmpty(OrderSn) {
		err = gerror.New("订单号为空")
		return
	}

	if err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		RebateLogger.Info(ctx, "检测订单信息")
		// 查询 app 订单信息
		if err = dao.PmsAppStay.Ctx(ctx).TX(tx).
			Where(dao.PmsAppStay.Columns().OrderSn, OrderSn).
			Scan(&StayInfo); err != nil {
			return
		}
		if g.IsEmpty(StayInfo) {
			err = gerror.New("住宿订单数据为空")
			return
		}
		if StayInfo.IsGetOpen != "Y" {
			err = gerror.New("未开启订单返现")
			return
		}
		if StayInfo.HotelGetScoreStatus != "WAIT" {
			err = gerror.New("订单状态不为返现处理中")
			return
		}
		RebateLogger.Info(ctx, "结算返现")
		// 查询订单外部支付退款和外部支付信息
		if PayAmount, err = dao.PmsTransaction.Ctx(ctx).TX(tx).
			Where(dao.PmsTransaction.Columns().OrderSn, OrderSn).
			WhereNot(dao.PmsTransaction.Columns().PayType, "BAL").
			Where(dao.PmsTransaction.Columns().PayStatus, "DONE").
			Group(dao.PmsTransaction.Columns().OrderSn).
			Sum(dao.PmsTransaction.Columns().PayAmount); err != nil {
			return
		}
		if PayAmount <= 0 {
			err = gerror.New("未产生除积分外的支付信息无法进行结算佣金")
			return
		}
		if RefundAmount, err = dao.PmsTransactionRefund.Ctx(ctx).TX(tx).
			Where(dao.PmsTransactionRefund.Columns().OrderSn, OrderSn).
			WhereNot(dao.PmsTransactionRefund.Columns().RefundType, "BAL").
			Where(dao.PmsTransactionRefund.Columns().RefundStatus, "DONE").
			Group(dao.PmsTransactionRefund.Columns().OrderSn).
			Sum(dao.PmsTransactionRefund.Columns().RefundAmount); err != nil {
			return
		}
		if YYConfig, err = service.BasicsConfig().GetYYConfig(ctx); err != nil {
			return
		}
		HotelGetAmountDecimal := decimal.NewFromFloat(PayAmount).Sub(decimal.NewFromFloat(RefundAmount)).Round(0)
		g.Log().Debugf(ctx, "HotelGetAmountDecimal:%f", HotelGetAmountDecimal.InexactFloat64())
		HotelGetAmount := HotelGetAmountDecimal.
			Mul(decimal.NewFromFloat(StayInfo.HotelGetRateScene).Div(decimal.NewFromFloat(100)).Round(0)).
			Mul(decimal.NewFromFloat(StayInfo.HotelGetRateVip)).
			Mul(decimal.NewFromFloat(YYConfig.ExchangeRate)).Round(0).InexactFloat64()
		g.Log().Debugf(ctx, "HotelGetAmount:%f", HotelGetAmount)
		// 结算给用户
		if err = service.AppMember().MemberBalanceChange(ctx, &input_app_member.MemberBalanceInp{
			MemberId:      StayInfo.MemberId,
			Scene:         "HOTEL",
			Type:          "AWARD",
			ChangeBalance: HotelGetAmount,
			OrderSn:       StayInfo.OrderSn,
			Des:           "下单返积分",
		}, tx); err != nil {
			return
		}
		// 记录结算结果
		if _, err = dao.PmsAppStay.Ctx(ctx).TX(tx).WherePri(StayInfo.Id).Data(g.Map{
			dao.PmsAppStay.Columns().HotelGetScoreStatus: "SUCCESS",
			dao.PmsAppStay.Columns().HotelGetAmount:      HotelGetAmount,
		}).UpdateAndGetAffected(); err != nil {
			return
		}
		RebateLogger.Info(ctx, "RUN_SUCCESS_ReturnBrokerage")
		return err
	}); err != nil {
		RebateLogger.Info(ctx, "RUN_FAIL_ReturnScore")
		return err
	}
	return
}

// HandleSpaReturnScore 用户下单返积分
func HandleSpaReturnScore(ctx context.Context, msg amqp.Delivery) (err error) {
	var (
		body         = msg.Body
		OrderSn      string
		SpaOrder     *entity.SpaOrder
		YYConfig     *model.YYConfig
		PayAmount    float64
		RefundAmount float64
	)
	OrderSn = gvar.New(body).String()
	if g.IsEmpty(OrderSn) {
		err = gerror.New("订单号为空")
		return
	}

	if err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		RebateLogger.Info(ctx, "检测订单信息")
		// 查询 app 订单信息
		if err = dao.SpaOrder.Ctx(ctx).TX(tx).
			Where(dao.SpaOrder.Columns().OrderSn, OrderSn).
			Scan(&SpaOrder); err != nil {
			return
		}
		if g.IsEmpty(SpaOrder) {
			err = gerror.New("住宿订单数据为空")
			return
		}
		if SpaOrder.IsGetOpen != "Y" {
			err = gerror.New("未开启订单返现")
			return
		}
		if SpaOrder.SpaGetScoreStatus != "WAIT" {
			err = gerror.New("订单状态不为返现处理中")
			return
		}
		RebateLogger.Info(ctx, "结算返现")
		// 查询订单外部支付退款和外部支付信息
		if PayAmount, err = dao.PmsTransaction.Ctx(ctx).TX(tx).
			Where(dao.PmsTransaction.Columns().OrderSn, OrderSn).
			WhereNot(dao.PmsTransaction.Columns().PayType, "BAL").
			Where(dao.PmsTransaction.Columns().PayStatus, "DONE").
			Group(dao.PmsTransaction.Columns().OrderSn).
			Sum(dao.PmsTransaction.Columns().PayAmount); err != nil {
			return
		}
		if PayAmount <= 0 {
			err = gerror.New("未产生除积分外的支付信息无法进行结算佣金")
			return
		}
		if RefundAmount, err = dao.PmsTransactionRefund.Ctx(ctx).TX(tx).
			Where(dao.PmsTransactionRefund.Columns().OrderSn, OrderSn).
			WhereNot(dao.PmsTransactionRefund.Columns().RefundType, "BAL").
			Where(dao.PmsTransactionRefund.Columns().RefundStatus, "DONE").
			Group(dao.PmsTransactionRefund.Columns().OrderSn).
			Sum(dao.PmsTransactionRefund.Columns().RefundAmount); err != nil {
			return
		}
		if YYConfig, err = service.BasicsConfig().GetYYConfig(ctx); err != nil {
			return
		}
		SpaGetAmountDecimal := decimal.NewFromFloat(PayAmount).Sub(decimal.NewFromFloat(RefundAmount)).Round(0)
		g.Log().Debugf(ctx, "HotelGetAmountDecimal:%f", SpaGetAmountDecimal.InexactFloat64())
		SpaGetAmount := SpaGetAmountDecimal.
			Mul(decimal.NewFromFloat(SpaOrder.SpaGetRateScene).Div(decimal.NewFromFloat(100)).Round(0)).
			Mul(decimal.NewFromFloat(SpaOrder.SpaGetRateVip)).
			Mul(decimal.NewFromFloat(YYConfig.ExchangeRate)).Round(0).InexactFloat64()
		g.Log().Debugf(ctx, "HotelGetAmount:%f", SpaGetAmount)
		// 结算给用户
		if err = service.AppMember().MemberBalanceChange(ctx, &input_app_member.MemberBalanceInp{
			MemberId:      gvar.New(SpaOrder.MemberId).Int(),
			Scene:         "SPA",
			Type:          "AWARD",
			ChangeBalance: SpaGetAmount,
			OrderSn:       SpaOrder.OrderSn,
			Des:           "下单返积分",
		}, tx); err != nil {
			return
		}
		// 记录结算结果
		if _, err = dao.PmsAppStay.Ctx(ctx).TX(tx).WherePri(SpaOrder.Id).Data(g.Map{
			dao.PmsAppStay.Columns().HotelGetScoreStatus: "SUCCESS",
			dao.PmsAppStay.Columns().HotelGetAmount:      SpaGetAmount,
		}).UpdateAndGetAffected(); err != nil {
			return
		}
		RebateLogger.Info(ctx, "RUN_SUCCESS_ReturnBrokerage")
		return err
	}); err != nil {
		RebateLogger.Info(ctx, "RUN_FAIL_ReturnScore")
		return err
	}
	return
}

// HandleCarReturnScore 用户下单返积分
func HandleCarReturnScore(ctx context.Context, msg amqp.Delivery) (err error) {
	var (
		body         = msg.Body
		OrderSn      string
		CarOrder     *entity.CarOrder
		YYConfig     *model.YYConfig
		PayAmount    float64
		RefundAmount float64
	)
	OrderSn = gvar.New(body).String()
	if g.IsEmpty(OrderSn) {
		err = gerror.New("订单号为空")
		return
	}

	if err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		RebateLogger.Info(ctx, "检测订单信息")
		// 查询 app 订单信息
		if err = dao.CarOrder.Ctx(ctx).TX(tx).
			Where(dao.CarOrder.Columns().OrderSn, OrderSn).
			Scan(&CarOrder); err != nil {
			return
		}
		if g.IsEmpty(CarOrder) {
			err = gerror.New("住宿订单数据为空")
			return
		}
		if CarOrder.IsGetOpen != "Y" {
			err = gerror.New("未开启订单返现")
			return
		}
		if CarOrder.CarGetScoreStatus != "WAIT" {
			err = gerror.New("订单状态不为返现处理中")
			return
		}
		RebateLogger.Info(ctx, "结算返现")
		// 查询订单外部支付退款和外部支付信息
		if PayAmount, err = dao.PmsTransaction.Ctx(ctx).TX(tx).
			Where(dao.PmsTransaction.Columns().OrderSn, OrderSn).
			WhereNot(dao.PmsTransaction.Columns().PayType, "BAL").
			Where(dao.PmsTransaction.Columns().PayStatus, "DONE").
			Group(dao.PmsTransaction.Columns().OrderSn).
			Sum(dao.PmsTransaction.Columns().PayAmount); err != nil {
			return
		}
		if PayAmount <= 0 {
			err = gerror.New("未产生除积分外的支付信息无法进行结算佣金")
			return
		}
		if RefundAmount, err = dao.PmsTransactionRefund.Ctx(ctx).TX(tx).
			Where(dao.PmsTransactionRefund.Columns().OrderSn, OrderSn).
			WhereNot(dao.PmsTransactionRefund.Columns().RefundType, "BAL").
			Where(dao.PmsTransactionRefund.Columns().RefundStatus, "DONE").
			Group(dao.PmsTransactionRefund.Columns().OrderSn).
			Sum(dao.PmsTransactionRefund.Columns().RefundAmount); err != nil {
			return
		}
		if YYConfig, err = service.BasicsConfig().GetYYConfig(ctx); err != nil {
			return
		}
		CarGetAmountDecimal := decimal.NewFromFloat(PayAmount).Sub(decimal.NewFromFloat(RefundAmount)).Round(0)
		g.Log().Debugf(ctx, "HotelGetAmountDecimal:%f", CarGetAmountDecimal.InexactFloat64())
		CarGetAmount := CarGetAmountDecimal.
			Mul(decimal.NewFromFloat(CarOrder.CarGetRateScene).Div(decimal.NewFromFloat(100)).Round(0)).
			Mul(decimal.NewFromFloat(CarOrder.CarGetRateVip)).
			Mul(decimal.NewFromFloat(YYConfig.ExchangeRate)).Round(0).InexactFloat64()
		g.Log().Debugf(ctx, "HotelGetAmount:%f", CarGetAmount)
		// 结算给用户
		if err = service.AppMember().MemberBalanceChange(ctx, &input_app_member.MemberBalanceInp{
			MemberId:      gvar.New(CarOrder.MemberId).Int(),
			Scene:         "CAR",
			Type:          "AWARD",
			ChangeBalance: CarGetAmount,
			OrderSn:       CarOrder.OrderSn,
			Des:           "下单返积分",
		}, tx); err != nil {
			return
		}
		// 记录结算结果
		if _, err = dao.PmsAppStay.Ctx(ctx).TX(tx).WherePri(CarOrder.Id).Data(g.Map{
			dao.PmsAppStay.Columns().HotelGetScoreStatus: "SUCCESS",
			dao.PmsAppStay.Columns().HotelGetAmount:      CarGetAmount,
		}).UpdateAndGetAffected(); err != nil {
			return
		}
		RebateLogger.Info(ctx, "RUN_SUCCESS_ReturnBrokerage")
		return err
	}); err != nil {
		RebateLogger.Info(ctx, "RUN_FAIL_ReturnScore")
		return err
	}
	return
}

// HandleFoodReturnScore 用户下单返积分
func HandleFoodReturnScore(ctx context.Context, msg amqp.Delivery) (err error) {
	var (
		body         = msg.Body
		OrderSn      string
		FoodOrder    *entity.FoodOrder
		YYConfig     *model.YYConfig
		PayAmount    float64
		RefundAmount float64
	)
	OrderSn = gvar.New(body).String()
	if g.IsEmpty(OrderSn) {
		err = gerror.New("订单号为空")
		return
	}

	if err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		RebateLogger.Info(ctx, "检测订单信息")
		// 查询 app 订单信息
		if err = dao.FoodOrder.Ctx(ctx).TX(tx).
			Where(dao.FoodOrder.Columns().OrderSn, OrderSn).
			Scan(&FoodOrder); err != nil {
			return
		}
		if g.IsEmpty(FoodOrder) {
			err = gerror.New("住宿订单数据为空")
			return
		}
		if FoodOrder.IsGetOpen != "Y" {
			err = gerror.New("未开启订单返现")
			return
		}
		if FoodOrder.FoodGetScoreStatus != "WAIT" {
			err = gerror.New("订单状态不为返现处理中")
			return
		}
		RebateLogger.Info(ctx, "结算返现")
		// 查询订单外部支付退款和外部支付信息
		if PayAmount, err = dao.PmsTransaction.Ctx(ctx).TX(tx).
			Where(dao.PmsTransaction.Columns().OrderSn, OrderSn).
			WhereNot(dao.PmsTransaction.Columns().PayType, "BAL").
			Where(dao.PmsTransaction.Columns().PayStatus, "DONE").
			Group(dao.PmsTransaction.Columns().OrderSn).
			Sum(dao.PmsTransaction.Columns().PayAmount); err != nil {
			return
		}
		if PayAmount <= 0 {
			err = gerror.New("未产生除积分外的支付信息无法进行结算佣金")
			return
		}
		if RefundAmount, err = dao.PmsTransactionRefund.Ctx(ctx).TX(tx).
			Where(dao.PmsTransactionRefund.Columns().OrderSn, OrderSn).
			WhereNot(dao.PmsTransactionRefund.Columns().RefundType, "BAL").
			Where(dao.PmsTransactionRefund.Columns().RefundStatus, "DONE").
			Group(dao.PmsTransactionRefund.Columns().OrderSn).
			Sum(dao.PmsTransactionRefund.Columns().RefundAmount); err != nil {
			return
		}
		if YYConfig, err = service.BasicsConfig().GetYYConfig(ctx); err != nil {
			return
		}
		FoodGetAmountDecimal := decimal.NewFromFloat(PayAmount).Sub(decimal.NewFromFloat(RefundAmount)).Round(0)
		g.Log().Debugf(ctx, "HotelGetAmountDecimal:%f", FoodGetAmountDecimal.InexactFloat64())
		FoodGetAmount := FoodGetAmountDecimal.
			Mul(decimal.NewFromFloat(FoodOrder.FoodGetRateScene).Div(decimal.NewFromFloat(100)).Round(0)).
			Mul(decimal.NewFromFloat(FoodOrder.FoodGetRateVip)).
			Mul(decimal.NewFromFloat(YYConfig.ExchangeRate)).Round(0).InexactFloat64()
		g.Log().Debugf(ctx, "HotelGetAmount:%f", FoodGetAmount)
		// 结算给用户
		if err = service.AppMember().MemberBalanceChange(ctx, &input_app_member.MemberBalanceInp{
			MemberId:      gvar.New(FoodOrder.MemberId).Int(),
			Scene:         "FOOD",
			Type:          "AWARD",
			ChangeBalance: FoodGetAmount,
			OrderSn:       FoodOrder.OrderSn,
			Des:           "下单返积分",
		}, tx); err != nil {
			return
		}
		// 记录结算结果
		if _, err = dao.FoodOrder.Ctx(ctx).TX(tx).WherePri(FoodOrder.Id).Data(g.Map{
			dao.FoodOrder.Columns().FoodGetScoreStatus: "SUCCESS",
			dao.FoodOrder.Columns().FoodGetAmount:      FoodGetAmount,
		}).UpdateAndGetAffected(); err != nil {
			return
		}
		RebateLogger.Info(ctx, "RUN_SUCCESS_ReturnBrokerage")
		return err
	}); err != nil {
		RebateLogger.Info(ctx, "RUN_FAIL_ReturnScore")
		return err
	}
	return
}

// HandleInviteAward 邀新首单推荐人奖励
func HandleInviteAward(ctx context.Context, msg amqp.Delivery) (err error) {
	var (
		body                  = msg.Body
		OrderSn               string
		StayInfo              *entity.PmsAppStay
		CheckStayInfo         *entity.PmsAppStay
		checkinStatusVar      *gvar.Var
		ReferrerInfo          *entity.PmsMember
		InviteNewRewardConfig *model.InviteNewRewardConfig
	)
	OrderSn = gvar.New(body).String()
	if g.IsEmpty(OrderSn) {
		err = gerror.New("订单号为空")
		return
	}
	// 获取奖励配置
	if InviteNewRewardConfig, err = service.BasicsConfig().GetInviteNewRewardConfig(ctx); err != nil {
		return
	}
	if InviteNewRewardConfig.IsInviteRewardOpen != 1 {
		err = gerror.New("未开启邀新奖励")
		return
	}
	// 获取奖励
	if err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		RebateLogger.Info(ctx, "检测订单信息")
		// 查询 app 订单信息
		if err = dao.PmsAppStay.Ctx(ctx).TX(tx).
			Where(dao.PmsAppStay.Columns().OrderSn, OrderSn).
			Scan(&StayInfo); err != nil {
			return
		}
		if g.IsEmpty(StayInfo) {
			err = gerror.New("住宿订单数据为空")
			return
		}
		if g.IsEmpty(StayInfo.Referrer) {
			err = gerror.New("没有推荐人无需处理推荐人推荐奖励")
			return
		}
		if checkinStatusVar, err = dao.PmsAppReservation.Ctx(ctx).TX(tx).
			Where(dao.PmsAppReservation.Columns().OrderSn, OrderSn).
			Group(dao.PmsAppReservation.Columns().CheckinStatus).
			Fields("GROUP_CONCAT(checkin_status) as checkin_status").
			Value(); err != nil {
			return
		}
		if checkinStatusVar.String() != "checked_out" {
			err = gerror.New("订单未完结无法处理推荐人推荐奖励")
			return
		}
		CheckStayInfo = new(entity.PmsAppStay)
		// 是否是首次下单
		if err = dao.PmsAppStay.Ctx(ctx).
			Where(dao.PmsAppStay.Columns().MemberId, StayInfo.MemberId).
			Where(dao.PmsAppStay.Columns().OrderStatus, "HAVE_PAID").
			OrderAsc(dao.PmsAppStay.Columns().Id).
			Scan(&CheckStayInfo); err != nil {
			return
		}
		if g.IsEmpty(CheckStayInfo) {
			RebateLogger.Info(ctx, "无订单不需要处理下单之后邀请人获得奖励")
		}
		if CheckStayInfo.OrderSn != OrderSn {
			RebateLogger.Info(ctx, "非首次下单不进行结算")
		}
		RebateLogger.Info(ctx, "结算首次被邀请人下单之后邀请人获得奖励")
		// 查看推荐人信息
		if err = dao.PmsMember.Ctx(ctx).TX(tx).Where(dao.PmsMember.Columns().Id, StayInfo.Referrer).Scan(&ReferrerInfo); err != nil && !errors.Is(err, sql.ErrNoRows) {
			return
		}
		if g.IsEmpty(ReferrerInfo) {
			err = gerror.New("推荐人不存在无法处理推荐人推荐奖励")
			return
		}
		if ReferrerInfo.IsInviteRewards == "Y" {
			RebateLogger.Info(ctx, "推荐人已获得奖励无法处理推荐人推荐奖励")
			return
		}
		ChangeBalance := 0.0
		if ReferrerInfo.RebateMode == "STAFF" {
			ChangeBalance = InviteNewRewardConfig.StaffRewardBalance
		} else if ReferrerInfo.RebateMode == "CHANNEL" {
			ChangeBalance = InviteNewRewardConfig.ChannelRewardBalance
		} else if ReferrerInfo.RebateMode == "MEMBER" {
			ChangeBalance = InviteNewRewardConfig.MemberRewardBalance
		} else {
			err = gerror.New("推荐人推荐奖励模式异常")
			return
		}
		// 发放积分奖励
		if err = service.AppMember().MemberBalanceChange(ctx, &input_app_member.MemberBalanceInp{
			MemberId:      StayInfo.Referrer,
			Scene:         "SYSTEM",
			Type:          "AWARD",
			ChangeBalance: ChangeBalance,
			OrderSn:       OrderSn,
			Des:           "邀请人首单奖励",
		}, tx); err != nil {
			return
		}
		// 修改注册人发放过推荐人奖励
		if _, err = dao.PmsMember.Ctx(ctx).TX(tx).WherePri(StayInfo.MemberId).Data(g.Map{
			dao.PmsMember.Columns().IsInviteRewards: "Y",
		}).UpdateAndGetAffected(); err != nil {
			return
		}
		RebateLogger.Info(ctx, "RUN_SUCCESS_HandleInviteAward")
		return err
	}); err != nil {
		RebateLogger.Info(ctx, "RUN_FAIL_HandleInviteAward")
		return err
	}
	return
}
